from django.db import models
from django.db import connection
from django.contrib.auth.models import AbstractUser
from ac.exception import *
from method import tools
from method.redis import write_or_read_func_cache
from tb_menu.function.update_menu import updateMenu

# Create your models here.

__all__ = [
    "Duty",
    "OrgRole",
    "OrgLevel",
    "Org",
    "Site",
    "MyUser",
    "UserOrgMap",
    "OrgManager",
    "Status",
    "UserCheck",
    "Project",
    "UserProjectMap",
    "OS",
    "PushToken",
    "Role",
    "Function",
    "UserRoleMap",
    "RoleFunctionMap",
    "LoginLog",
    "UpdateLog",
    "LoginToken",
]


class RoleFunc(object):
    def __init__(self, role, new_func):
        role = isinstance(role, str) and eval(role) or role
        new_func = isinstance(new_func, str) and eval(new_func) or new_func
        if isinstance(role, list):
            self.role = tools.list_str_to_int(role)[0]
        else:
            self.role = int(role)
        self.new_func = tools.list_str_to_int(new_func)     # 初始化为数字列表类型（默认http传递的是str类型）

    def check_function(self):
        self.cursor = connection.cursor()
        self.cursor.execute("SELECT function_id FROM tb_role_function_map WHERE role_id=%s" % str(self.role))
        self.old_func = [func[0] for func in self.cursor.fetchall()]  # 初始化为列表类型（SQL语句查询结果为二元元祖类型）

        if not list(set(self.old_func).difference(set(self.new_func))) \
                and not list(set(self.new_func).difference(set(self.old_func))):
            # 检查新旧两个功能ID的列表是否存在差集，两个差集都为空表示两个列表完全相同
            return False
        else:
            return True

    def add_role_function(self):
        """
        接收角色和功能的ID参数，Role只能是一个ID参数，Function可以是一个ID的列表
        :param role: Role ID
        :param function: Function ID  or  Function ID List
        :return:
        """
        exist = []
        succeed = []
        for func in self.new_func:
            obj, status = RoleFunctionMap.objects.get_or_create(role_id=self.role, function_id=func)
            if status:
                succeed.append(func)
            else:
                exist.append(func)
        if exist:
            return "exist: '%s',succeed: '%s'!" % (str(exist), str(succeed))
        else:
            return "succeed: '%s'!" % str(succeed)

    def update_role_function(self):
        """
        接收角色和功能的ID参数，Role只能是一个ID参数，Function可以是一个ID的列表
        这里
        :param role: Role ID
        :param new_func: 新的功能ID列表
        :return:
        """
        if not self.check_function():
            return "當前參數不需要更新!"

        delete = list(set(self.old_func).difference(set(self.new_func)))      # 获取旧的有的，新的却没有的，等待删除
        create = list(set(self.new_func).difference(set(self.old_func)))      # 获取新的有的，旧的却没有的，等待添加
        if len(delete) == len(create):                              # 新旧功能列表长度相同则不需要补齐，否则补None
            pass
        elif len(delete) > len(create):
            tools.supplying_list(create, len(delete) - len(create))
        else:
            tools.supplying_list(delete, len(create) - len(delete))
        for old, new in zip(delete, create):
            if old:
                func_obj = RoleFunctionMap.objects.filter(function_id=old)[0]
                if new:
                    if self.cursor.execute("SELECT id FROM tb_function WHERE id = %s" % new):   # 确认新功能是否存在
                        func_obj.function_id = new
                        func_obj.save()
                    else:
                        raise ValueError("功能的ID '%s' 不存在!" % new)
                else:
                    func_obj.delete()       # 旧的存在新的却没有，代表被取消的功能，执行删除
            else:
                if self.cursor.execute("SELECT id FROM tb_function WHERE id = %s" % new):       # 确认新功能是否存在
                    RoleFunctionMap.objects.create(role_id=self.role, function_id=new)
                else:
                    raise ValueError("功能的ID '%s' 不存在!" % new)
        return "Update successfully!"


class Duty(models.Model):
    """
    职务表
    """
    name = models.CharField(max_length=50)
    code = models.CharField(max_length=50, null=True)
    desc = models.CharField(max_length=500, null=True)

    class Meta:
        db_table = "tb_duty"

    def __str__(self):
        return self.name


class OrgLevel(models.Model):
    """
    组织架构等级表，记录每个组织单元属于哪一个级别
    """
    level = models.IntegerField(unique=True, primary_key=True)
    level_name = models.CharField(max_length=100)
    level_code = models.CharField(max_length=50)
    id = models.IntegerField(unique=True)
    # duty = models.ForeignKey(Duty)

    class Meta:
        db_table = "tb_org_level"

    def __str__(self):
        return self.level_name

    def get_new_level(self):
        obj = OrgLevel.objects.all().order_by("-level")
        if obj:
            return self.get_level(front=obj[0].level)
        else:
            return 10

    def check_level(self, **kwargs):
        result = OrgLevel.objects.filter(**kwargs)
        if result:
            return result
        else:
            return None

    def get_level(self, front=0, later=0):
        """
        添加组织，请传入front，later为0。添加顶级组织，请传入later，front为0。中间插入需要传入前后两个参数
        :param front: 前面的level
        :param later: 后面的level
        :return:
        """
        if isinstance(front, str):
            front = int(front)
        if isinstance(later, str):
            later = int(later)
        if not (front or later):             # 不能兩個參數都為空，無法計算新級數
            raise ValueError("不能兩個參數都是無效值")
        else:
            if front:                        # 假如前參存在，判斷數據庫是否存在這個級別，不存在拋出異常
                if not self.check_level(level=front):
                    raise ValueError("參數 '%s' 不存在于數據庫中" % front)
            elif later:                      # 假如后參存在，判斷數據庫是否存在這個級別，不存在拋出異常
                if not self.check_level(level=later):
                    raise ValueError("參數 '%s' 不存在于數據庫中" % later)

        if front != 0 and later == 0:        # 假如只提供front參數，默認為最後的一個級別，作加5處理即可
            later_level = OrgLevel.objects.values('level').order_by('-level')[0]["level"]
            if front != later_level:
                raise ValueError("應為你前面參數是0，所以第二個參數必須是填最大的組織！")
            number = front + 5
        elif front == 0 and later != 0:        # 假如只提供later參數，默認為最前的一個級別
            later_level = OrgLevel.objects.values('level').order_by('level')[0]["level"]
            if later != later_level:
                raise ValueError("如果你後面的參數是0，那麼你前面的參數應該是最小的組織")
            number = later - int((later-front)/2)
        else:
            number = later - int((later-front)/2)

        # 假設新生成的level在數據庫中存在，那麼用戶放入的兩個參數不滿足最前，最後，連續兩個的某個要求
        if self.check_level(level=number):
            raise ValueError("你輸入的參數必須是連續的兩個")
        return number

    def serial_level(self, up=True, value=1):
        """
        查询指定級數的更高級或更低級的OrgLevel對象
        :param up: 默認為True，代表獲取更高級
        :param value: 默認為1，代表跨越度為1
        :return: 返回一個OrgLevel對象
        """
        lis = OrgLevel.objects.all().order_by('level')      # 返回一個按level升序排列的對象列表
        for i, v in enumerate(lis):
            if v.level == self.level:
                index = i
                break

        if up:
            if index == 0:
                raise ValueError("當前是最高等級，無法獲得更高的了")
            result = lis[index-value]
        else:
            if index == len(lis):
                raise ValueError("當前等級是最低的了，無法獲得更低的了")
            result = lis[index+value]

        return result


class Org(models.Model):
    """
    组织架构单元表，属于组织链中的单一节点，如'CNSBG'
    """
    org_name = models.CharField(max_length=100)
    parent_id = models.IntegerField(null=True)
    org_level = models.ForeignKey(OrgLevel, default=3)
    is_active = models.BooleanField(default=True)
    create_date = models.DateTimeField(auto_now_add=True)
    org_code = models.CharField(max_length=50)
    cost_code = models.CharField(max_length=50, null=True)
    org_desc = models.CharField(max_length=500, null=True)
    org_desc2 = models.CharField(max_length=500, null=True)
    org_people = models.IntegerField(default=0, null=True)
    org_people_all = models.IntegerField(default=0, null=True)

    class Meta:
        db_table = "tb_org"

    def __str__(self):
        return self.org_name

    def get_full_org(self, listType=False):
        """
        默认返回字符串类型的Org鏈，中间以'-'符号分隔；
        listType為True時返回列表類型的Org鏈
        :param listType: False
        :return: string full Org
        """
        parent_id = self.parent_id
        if listType:
            org = [self.org_name]
        else:
            org = self.org_name
        while parent_id:
            org_obj = Org.objects.filter(pk=parent_id, is_active=True)

            # 假如用parent查询的Org_id不存在，（assert False）抛出AssertionError异常
            assert org_obj, ("org_id '%s' 不存在" % parent_id)
            # if not org_obj:


            parent_id = org_obj[0].parent_id
            if listType:
                org = org.insert(0, org_obj[0].org_name)
            else:
                org = org_obj[0].org_name + '-' + org
        return org

    def org_manager(self, key=None):
        manage = UserOrgMap.objects.filter(org=self, org_role__level=1)
        if manage:
            if key:
                return eval("manage[0].%s" % key)
            else:
                return manage[0]
        else:
            return None

    def save(self, force_insert=False, force_update=False, using=None,
             update_fields=None):
        max_level = Org.objects.filter(is_active=True).order_by("org_level")

        if not max_level:                          # 如果数据库中没有有效的数据，那么就认为当前的数据为最大的，不作检查
            return super(Org, self).save(force_insert, force_update, using, update_fields)

        if self.org_level.level != max_level[0].org_level.level:            # 如果不是最高级别的组织都要进行有效性检查
            assert self.parent_id, ("'parent_id' 不能為空!", )

            parent_obj = Org.objects.filter(pk=self.parent_id)

            assert parent_obj, ("參數'%s'是無效的!" % self.parent_id,)

            if self.org_level_id <= parent_obj[0].org_level_id:         # 新增的組織節點級別不能大於父級節點（數字越小級別越高）
                raise ValueError(
                    "你所填寫的上級組織的級別必須大於當前的組織 '%s'!" % parent_obj[0].org_name)

            # if self.org_code:  # 組織代碼的唯一性檢測, 為空時不檢測
            #     obj = Org.objects.filter(org_code__iexact=self.org_code)
            #     if getattr(self, "pk"):                 # Update have pk
            #         obj = obj.exclude(pk=self.pk)       # 去除查询结果中的自己
            #         if obj:                             # 修改时假如有其他的ORG对象的组织代码和自己一致，那么抛出异常
            #             raise ValueError(
            #                 "The organization code '%s' has been used！" % self.org_code
            #             )
            #     else:                          # Create not have pk
            #         assert not obj, ValueError(                       # 存在就抛出异常
            #             "The organization code '%s' has been used！" % self.org_code)

        return super(Org, self).save(force_insert, force_update, using, update_fields)

    def max_org_level(self):
        return Org.objects.values("org_level").order_by("org_level")[0]["org_level"]
    # def delete_org(self):
    #     self.is_active = False
    #     self.save()

        # for child in

    # def get_childs(self):


class Site(models.Model):
    site_code = models.CharField(max_length=50, unique=True)
    site_name = models.CharField(max_length=50)
    area_code = models.CharField(max_length=10, null=True)
    create_date = models.DateTimeField(auto_now_add=True)

    class Meta:
        db_table = "tb_site"

    def __str__(self):
        return self.site_code


class Status(models.Model):
    """
    状态表，用来存放一些可以签核过程中的状态名称，
    如用户注册时的：直属主管待签核
    如系统注册时的：Project负责人待签核、AC管理员待签核
    """
    _STATUS_TYPE_CHOICES = (('User', u'用戶類型'), ('System', u'系統類型'))

    status_code = models.IntegerField(unique=True, primary_key=True)
    status_name = models.CharField(max_length=50)
    status_type = models.CharField(max_length=100, null=True, choices=_STATUS_TYPE_CHOICES)
    status_desc = models.CharField(max_length=500, null=True)
    id = models.IntegerField(unique=True)

    class Meta:
        db_table = "tb_status"

    def __str__(self):
        return self.status_name


class MyUser(AbstractUser):
    """
    重载Django内置用户系统中的用户表
    新建用户时，必须先调用一下create_action()方法 或 调用save()方法时写为save(force_insert=True)
    """
    SEX_CHOICES = ((0, u"男",), (1, u"女",))
    # SEX_CHOICES = ("男", "女",)
    # org = models.ManyToManyField(Org)
    NFC_id = models.CharField(max_length=100, null=True)
    ext = models.CharField(max_length=50, null=True, verbose_name="分机号")
    short_number = models.CharField(max_length=50, null=True)
    mobile_phone = models.CharField(max_length=50, null=True)
    site = models.ForeignKey(Site)
    head = models.CharField(null=True, max_length=500, help_text="將IP:端口+本字段內容進行拼接即可獲取相應圖片")
    sign = models.CharField(null=True, max_length=500, help_text="將IP:端口+本字段內容進行拼接即可獲取相應圖片")
    status = models.ForeignKey(Status, related_query_name='MU_query_status')
    entry_date = models.DateField(verbose_name="入職日期")
    sex = models.CharField(max_length=10, choices=SEX_CHOICES)
    duty = models.ForeignKey(Duty, null=True)
    motto = models.CharField(max_length=500, null=True)

    REQUIRED_FIELDS = ['email', 'site_id', 'status_id', 'entry_date', 'sex']

    class Meta:
        db_table = "tb_user"

    def __str__(self):
        return self.username

    def create_action(self):                 # 告诉系统我正在执行新建用户的操作
        self.force_insert = True
        return True

    def check_info(self):
        """
        定义对象中各属性的输入规范
        :return: None or AssertionError异常
        """

        def check_username():
            if self.username.isalpha():
                raise CheckAttribute("工號不能為全字符")

            elif len(self.username) < 6:
                raise CheckAttribute("工號長度不能小于六位數")

            elif len(self.username) > 8:
                raise CheckAttribute("工號長度不能大于八位數")

            self.username = self.username.upper()                   # 判断格式无误后将首字母大写，工号验证结束
            return True

        def check_pwd():
            if len(self.password) == 77:                            # Django加密后的密码为77位长度，假设为77即默认为已加密过的密码
                return True
            elif len(self.password) < 6 or len(self.password) > 12:
                raise CheckAttribute("密碼的長度範圍為6~12")

            self.set_password(self.password)                        # 驗證密碼格式無誤后進行加密操作
            return True

        def check_email():
            if '@' not in self.email:
                raise CheckAttribute("請輸入正確的郵箱地址")

            return True

        def check_other():
            _sex = dict(self.SEX_CHOICES)
            if self.sex in _sex.keys():
                self.sex = _sex[self.sex]
                return True
        try:
            check_username()
            check_pwd()
            check_email()
            check_other()
            return True, None
        except CheckAttribute as error:
            return False, str(error)

    def get_user_role_all(self, PID=False):
        # if PID:
        #     project = Project.objects.filter(PID=PID)
        #     assert project, ("PID '%s' nothingness" % PID)
        #
        #     user_project_map = UserProjectMap.objects.filter(user=self, project=project[0])
        #     # assert user_project_map, ("You don't have access to '%s' system yet" % project[0].short_name)
        # else:
        #     user_project_map = self.UP_user.all()
        #
        # user_role = []
        # for m in user_project_map:
        #     user_role += m.UR_UPM.all()
        #
        # return user_role
        if PID:
            user_role_obj = self.UR_user.filter(role__project__PID=PID, role__is_active=True)
        else:
            user_role_obj = UserRoleMap.objects.filter(user=self, role__is_active=True)

        role_all = [user_role.role for user_role in user_role_obj]
        return role_all

    def get_org_str(self):
        org_list = UserOrgMap.objects.filter(user=self)
        if len(org_list) > 1:
            result = ""
            for org in org_list:
                result += org.org.get_full_org() + "|"
            return result[:-1]          # 去掉最後面多餘的一個'|'
        elif len(org_list) == 1:
            return org_list[0].org.get_full_org()
        else:
            return ""

    def get_org_obj(self):
        org_list = UserOrgMap.objects.filter(user=self)
        return [org.org for org in org_list]

    def get_all_function(self):
        """
        获取当前用户所有的功能列表
        :return:  [function_name, ...]
        """
        @write_or_read_func_cache(self.username, "functions")
        def all_function():
            cursor = connection.cursor()
            sql = "SELECT name FROM tb_function WHERE id in " \
                      "(SELECT function_id FROM tb_role_function_map WHERE role_id in " \
                          "(SELECT role_id FROM tb_user_role_map WHERE user_id = %s))" % self.pk
            cursor.execute(sql)
            all_func = [func[0] for func in cursor.fetchall()]
            return all_func
        return all_function()

    def save(self, *args, **kwargs):
        result, message = self.check_info()         # 先检查输入的信息是否合乎规范
        assert result, (message)

        if hasattr(self, 'force_insert') or getattr(kwargs, "force_insert", False):   # 检查是否为新建用户
            status_id = 201                          # 新用户默认的状态为未激活
            # org_manager = self.org.OM_org.all()
            # assert org_manager, ("'%s' 组织没有设置管理员，请联系系统管理员进行添加" % self.org.get_full_org())
            self.is_active = 0                   # django自带的参数，为了避免前后矛盾，一并设为未激活，AC不使用这个属性
            self.status_id = status_id
            super(MyUser, self).save(*args, **kwargs)
            # UC = UserCheck()
            # UC.proposer_user = self
            # # UC.check_user = org_manager[0].manager
            # # UC.status_id = status_id
            # UC.save(force_insert=True)
        else:
            super(MyUser, self).save(*args, **kwargs)


class OrgRole(models.Model):
    name = models.CharField(max_length=100)
    code = models.CharField(max_length=50, null=True)
    desc = models.CharField(max_length=500, null=True)
    level = models.IntegerField(unique=True)       # 最大的是1，负责人，次之是助理2，成员是3，假设继续添加的话需要增加相应的代码
    create_date = models.DateTimeField(auto_now_add=True)

    class Meta:
        db_table = "tb_org_role"

    def __str__(self):
        return self.name


class UserOrgMap(models.Model):
    user = models.ForeignKey(MyUser, related_name="UO_user", related_query_name="UO_query_user")
    org = models.ForeignKey(Org, related_name="UO_org", related_query_name="UO_query_org")
    create_date = models.DateTimeField(auto_now_add=True)
    org_role = models.ForeignKey(OrgRole, default=3)

    class Meta:
        db_table = "tb_user_org"

    def __str__(self):
        return self.user.__str__() + "|" + self.org.get_full_org()

    def save(self, force_insert=False, force_update=False, using=None,
             update_fields=None):

        # 假设查不到结果就不会异常，假设查询有值则抛出异常
        if not getattr(self, "pk"):         # 如果没有pk就是插入数据，需要进行存在性检测
            assert not UserOrgMap.objects.filter(user=self.user, org=self.org),\
                ValueError("用戶 '%s' 已經存在 '%s' 組織中了" %
                                 (self.user.__str__(), self.org.__str__()))
        super(UserOrgMap, self).save(force_insert, force_update, using, update_fields)


# class OrgManager(models.Model):
#     """
#     记录每个组织单元的主管是谁
#     """
#     org = models.ForeignKey(Org, related_query_name='OM_query_org', related_name='OM_org')
#     manager = models.ForeignKey(MyUser, related_query_name='OM_query_manager', related_name='OM_user')
#     create_date = models.DateTimeField(auto_now_add=True)
#
#     class Meta:
#         db_table = "tb_org_manager"
#
#     def __str__(self):
#         return self.org.__str__() + "-" + self.manager.__str__()


class UserCheck(models.Model):
    """
    记录用户注册后的审核信息，主管审核完成后，代码会自动修改用户is_active属性为有效
    用户注册后，代码会自动根据用户的信息生成这张表，包含信息有：用户、主管、默认状态（待签核）
    """
    proposer_user = models.ForeignKey(MyUser, related_name="UC_proposer", related_query_name='UC_query_proposer')
    check_user = models.ForeignKey(MyUser, related_name="UC_check", related_query_name='UC_query_check')
    # status = models.ForeignKey(Status, related_query_name='UC_query_status')
    opinion = models.CharField(max_length=300, null=True)
    update_date = models.DateTimeField(auto_now=True)

    class Meta:
        db_table = "tb_user_check"

    def __str__(self):
        return self.proposer_user.__str__() + "-" + self.status.__str__()


class Project(models.Model):
    """
    记录所有需要使用AC账号的Project，并写入相应的Project信息，方便AC的识别与管理
    """
    PID = models.CharField(max_length=100, unique=True)
    # PID = models.IntegerField(unique=True)
    short_name = models.CharField(max_length=100)
    full_name = models.CharField(max_length=500)
    desc = models.CharField(max_length=1000)
    proposer = models.ForeignKey(MyUser, related_name="PP")
    manager = models.ForeignKey(MyUser, related_name="PM")
    opinion = models.CharField(max_length=500, null=True)
    http_address = models.CharField(max_length=200, null=True)
    server_ip = models.CharField(max_length=100, null=True)
    create_date = models.DateTimeField(auto_now_add=True)
    status = models.ForeignKey(Status)
    have_app = models.BooleanField(default=False)

    class Meta:
        db_table = "tb_project"

    def __str__(self):
        return self.short_name

    def get_modules(self):
        """
        取出'tb_aas_project2'表中属于当前Project的模块
        :return: 模块名称列表
        """
        cursor = connection.cursor()
        sql = "SELECT MODULENAME FROM tb_project_module WHERE PROJECTID=(" \
                "SELECT id FROM tb_project WHERE PID='%s')" % self.PID
        cursor.execute(sql)
        return [fetch[0] for fetch in cursor.fetchall()]


class UserProjectMap(models.Model):
    """
    用户和Project的关系表，可以用来延伸出用户在这个Project中的其他不同表现，如PushToken
    """
    user = models.ForeignKey(MyUser, related_name='UP_user')
    project = models.ForeignKey(Project, related_name='UP_project')
    create_date = models.DateTimeField(auto_now_add=True)

    class Meta:
        db_table = "tb_user_project_map"

    def __str__(self):
        return self.project.__str__() + "-" + self.user.__str__()


class OS(models.Model):
    """
    记录移动端的操作系统有哪些，便于针对不同系统作出不同应对
    """
    OS_name = models.CharField(max_length=50)
    OS_code_name = models.CharField(max_length=50, null=True)

    class Meta:
        db_table = "tb_OS"

    def __str__(self):
        return self.OS_name


class PushToken(models.Model):
    """
    每个用户登录移动平台后都会生成一个唯一的推送Token，用于对用户发送针对性的推送消息
    """
    token = models.CharField(max_length=100, unique=True)
    OS = models.ForeignKey(OS, related_query_name="PT_query_OS")
    user_project_map = models.ForeignKey(UserProjectMap, related_name="PT")
    create_date = models.DateTimeField(auto_now_add=True)

    class Meta:
        db_table = "tb_push_token"

    def __str__(self):
        return self.token


class Role(models.Model):
    """
    AC的角色系统表，记录所有的角色信息，但不包含角色功能
    """
    role_name = models.CharField(max_length=100)
    role_code = models.CharField(max_length=50, null=True)
    role_desc = models.CharField(max_length=500, null=True)
    func_list = models.TextField()
    project = models.ForeignKey(Project, related_name="R_project", related_query_name='R_query_project')
    create_date = models.DateTimeField(auto_now_add=True)
    is_active = models.BooleanField(default=True)
    type = models.SmallIntegerField(default=2)

    class Meta:
        db_table = "tb_project_role"

    def __str__(self):
        return self.role_name

    def get_role(self, pk):
        assert pk, ("缺少參數'PK'")
        if isinstance(pk, list):
            return Role.objects.select_related().filter(pk__in=pk, is_active=True)
        else:
            return Role.objects.select_related().filter(pk=pk, is_active=True)

    def save(self, force_insert=False, force_update=False, using=None,
             update_fields=None):
        check_role = Role.objects.filter(role_name=self.role_name, project_id=self.project_id, is_active=True)
        if check_role:
            if getattr(self, "pk"):         # 假如self存在id值
                if self.pk != check_role[0].pk:     # 那么查到的对象id和自己的id不相同就报错
                    raise ValueError("角色 '%s' 有重複存在資料庫中！" % self.role_name)
            else:                           # 假如不存在就是新建角色，已经存在就可以直接报错
                raise ValueError("角色 '%s' 已存在！" % self.role_name)

        super(Role, self).save(force_insert, force_update, using, update_fields)        # 继承父类的保存方法

        # if self.func_list:              # 保存后检测，因为必须是角色存在的情况下才能给角色添加功能
        #     obj = RoleFunc(self.id, self.func_list)
        #     obj.update_role_function()
        # else:                           # 沒有功能拋出異常
        #     raise ValueError("參數'func_list' 不能為空!")

    def get_function_all(self):
        """
        获取当前角色的所有功能，返回一个对象列表
        """
        RF_obj_list = self.RF_role.filter(function__is_active=True)         # 返回所有相关的RoleFunctionMap表的对象
        function = []
        for obj in RF_obj_list:
            function.append(obj.function)
        return function


class UserRoleMap(models.Model):
    """
    用户的角色Map表，多对多关系。
    记录用户有哪些角色。
    且一个用户可能有多个角色，一个角色可以被多个用户共用
    """
    user = models.ForeignKey(MyUser, related_name="UR_user", related_query_name="UR_query_user")
    role = models.ForeignKey(Role, related_name="UR_role", related_query_name="UR_query_role")

    class Meta:
        db_table = "tb_user_role_map"

    def __str__(self):
        return self.user.__str__() + '-' + self.role.__str__()

    def push(self):
        return updateMenu(self.user_id)

    def save(self, force_insert=False, force_update=False, using=None,
             update_fields=None):
        self.push()
        return super(UserRoleMap, self).save(force_insert, force_update, using, update_fields)

    # def delete(self, using=None):
    #     self.push()
    #     return super(UserRoleMap, self).delete(using)


# class ProjectRoleMap(models.Model):
#     """
#     项目和角色的映射表，多对多关系。
#     记录一个Project中包含哪些角色。
#     一个Project中可能有多个角色，一个角色也可能被多个Project共用
#     """
#     project = models.ForeignKey(Project)
#     role = models.ForeignKey(Role)
#
#     class Meta:
#         db_table = "tb_project_role_map"
#
#     def __str__(self):
#         return self.project.__str__() + '-' + self.role.__str__()


class Function(models.Model):
    """
    功能表
    记录角色的功能部分，可以被赋予角色，从而实现角色权限的自由组合与分配
    """
    code = models.CharField(max_length=50, null=True)
    name = models.CharField(max_length=50, unique=True)
    parent_id = models.IntegerField(null=True)
    parent_code = models.CharField(max_length=500, null=True)          # 填入所有父级Function的code，以'.'分隔
    full_code = models.CharField(max_length=500)            # 填入自上而下的所有code，以'.'分隔
    desc = models.CharField(max_length=500)
    desc2 = models.CharField(max_length=500, null=True)
    project = models.ForeignKey(Project, related_name="F_project")  # , related_query_name='F_query_project')
    definer = models.ForeignKey(MyUser, related_name="F_user")
    create_date = models.DateTimeField(auto_now_add=True)
    is_active = models.BooleanField(default=True)

    class Meta:
        db_table = "tb_function"

    def __str__(self):
        return self.name

    def get_child(self):
        child = Function.objects.filter(parent_id=self.pk)
        return child

    def get_child_all(self):
        pass


class RoleFunctionMap(models.Model):
    """
    角色和功能的映射表，多对多关系。
    记录一个角色包含哪些功能
    且一个角色可能有多个功能，一个功能也可能被多个角色共用
    """
    role = models.ForeignKey(Role, related_name='RF_role', related_query_name='RF_query_role')
    function = models.ForeignKey(Function, related_name='RF_function', related_query_name='RF_query_function')

    class Meta:
        db_table = "tb_role_function_map"

    def __str__(self):
        return self.role.__str__() + '-' + self.function.__str__()


# class UserChecklog(models.Model):
#     """
#     用户注册审核记录表
#     """
#     username = models.CharField(max_length=50)
#     check_username = models.CharField(max_length=50)
#     result = models.BooleanField()
#
#     class Meta:
#         db_table = "tb_user_check_log"
#
#     def __str__(self):
#         return self.username


class LoginLog(models.Model):
    """
    用户登录信息表。
    采集用户使用信息，为后期用户行为数据分析作基础
    """
    login_user = models.CharField(max_length=50)
    login_project = models.CharField(max_length=50)
    login_ip = models.GenericIPAddressField()
    login_date = models.DateTimeField(auto_now_add=True)
    logout_date = models.DateTimeField(auto_now=True, null=True)

    class Meta:
        db_table = "tb_login_log"

    def __str__(self):
        return self.login_user


class UpdateLog(models.Model):
    """
    变更操作记录表
    记录用户对角色、功能、组织架构、角色的功能、用户的角色等操作的变更记录
    """
    update_object = models.CharField(max_length=50)
    update_type = models.CharField(max_length=50)
    update_user = models.CharField(max_length=50)
    update_date = models.DateTimeField(auto_now=True)
    old = models.TextField(max_length=1000)
    new = models.TextField(max_length=1000)

    class Meta:
        db_table = "tb_update_log"

    def __str__(self):
        return self.update_object + '-' + self.update_type


class QRCode(models.Model):
    uid = models.CharField(max_length=50, unique=True)
    username = models.CharField(max_length=50)
    create_date = models.DateTimeField(auto_now=True)

    class Meta:
        db_table = "auth_QRcode"

    def __str__(self):
        return self.username


class LoginToken(models.Model):
    user_id = models.CharField(max_length=10)
    token = models.CharField(max_length=50)
    end_date = models.DateTimeField()

    class Meta:
        db_table = "tb_user_token"

    def __str__(self):
        return self.token

